AWS CDK で CustomResourceConfig クラスを使って、自動作成されるカスタムリソースをカスタマイズする
こんにちは、製造ビジネステクノロジー部の若槻です。
最近、AWS CDK で CustomResourceConfig というクラスが提供されていることを知りました。
このクラスの下記のメソッドを使うことで、AWS CDK で暗黙的に自動作成されるカスタムリソースをカスタマイズすることができます。
Name | Description |
---|---|
addLambdaRuntime | Lambda 関数のランタイムバージョン |
addLogRetentionLifetime | Lambda 関数のログ保持期間 |
addRemovalPolicy | Log group の削除ポリシー |
CustomResourceConfig の機能は CDK Aspects の仕組みにより実現されています。CDK Aspects を使うと、スコープ内のすべての construct の検証(すべてのバケットの暗号化など)や修正(タグの追加など)を行うことができ、その仕組が内部的に使われています。
注意点として CustomResourceConfig は Experimental な機能であるため、将来のバージョンで変更される可能性があります。
今回は CustomResourceConfig で利用可能な 3 つのメソッドを実際に試してみたいと思います。
試してみた
Amazon SES のReceiptRuleSet コンストラクトクラスで試してみます。この ReceiptRuleSet でdropSpam
を有効化した場合に、リソース作成時に Lambda 関数が暗黙的に自動作成されます。
CustomResourceConfig を使用しない場合
まずは CustomResourceConfig を使用しない場合を確認します。ここではスコープは stack にしていますが、app にすることも可能です。
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as ses from 'aws-cdk-lib/aws-ses';
export class SampleApp extends cdk.Stack {
constructor(scope: Construct, id: string) {
super(scope, id);
new ses.ReceiptRuleSet(this, 'RuleSet', {
dropSpam: true,
});
}
}
CDK Diff でデプロイした場合の差分を確認すると、SES や IAM のリソースに加えて Lambda 関数が作成されることが分かります。
npx cdk diff -- SampleApp
start: Building 2be77dbc0ced986cdd58818ebb2a0115fe12b5bddd8b10717cd7dfe27a786ee7:current_account-current_region
success: Built 2be77dbc0ced986cdd58818ebb2a0115fe12b5bddd8b10717cd7dfe27a786ee7:current_account-current_region
start: Publishing 2be77dbc0ced986cdd58818ebb2a0115fe12b5bddd8b10717cd7dfe27a786ee7:current_account-current_region
success: Published 2be77dbc0ced986cdd58818ebb2a0115fe12b5bddd8b10717cd7dfe27a786ee7:current_account-current_region
Hold on while we create a read-only change set to get a diff with accurate replacement information (use --no-change-set to use a less accurate but faster template-only diff)
Stack SampleApp
IAM Statement Changes
┌───┬────────────────────────────────────────────────────────────────────┬────────┬───────────────────────┬──────────────────────────────┬──────────────────────────────────────────────────────────────┐
│ │ Resource │ Effect │ Action │ Principal │ Condition │
├───┼────────────────────────────────────────────────────────────────────┼────────┼───────────────────────┼──────────────────────────────┼──────────────────────────────────────────────────────────────┤
│ + │ ${SingletonLambda224e77f9a32e4b4dac32983477abba16.Arn} │ Allow │ lambda:InvokeFunction │ Service:ses.amazonaws.com │ "StringEquals": { │
│ │ │ │ │ │ "AWS:SourceAccount": "${AWS::AccountId}" │
│ │ │ │ │ │ } │
├───┼────────────────────────────────────────────────────────────────────┼────────┼───────────────────────┼──────────────────────────────┼──────────────────────────────────────────────────────────────┤
│ + │ ${SingletonLambda224e77f9a32e4b4dac32983477abba16/ServiceRole.Arn} │ Allow │ sts:AssumeRole │ Service:lambda.amazonaws.com │ │
└───┴────────────────────────────────────────────────────────────────────┴────────┴───────────────────────┴──────────────────────────────┴──────────────────────────────────────────────────────────────┘
IAM Policy Changes
┌───┬────────────────────────────────────────────────────────────────┬────────────────────────────────────────────────────────────────────────────────┐
│ │ Resource │ Managed Policy ARN │
├───┼────────────────────────────────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────┤
│ + │ ${SingletonLambda224e77f9a32e4b4dac32983477abba16/ServiceRole} │ arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole │
└───┴────────────────────────────────────────────────────────────────┴────────────────────────────────────────────────────────────────────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)
(中略)
Resources
[+] AWS::SES::ReceiptRuleSet RuleSet RuleSetE30C6C48
[+] AWS::SES::ReceiptRule RuleSet/DropSpam/Rule RuleSetDropSpamRule5809F51B
[+] AWS::IAM::Role SingletonLambda224e77f9a32e4b4dac32983477abba16/ServiceRole SingletonLambda224e77f9a32e4b4dac32983477abba16ServiceRole3037F5B4
[+] AWS::Lambda::Function SingletonLambda224e77f9a32e4b4dac32983477abba16 SingletonLambda224e77f9a32e4b4dac32983477abba164533EA15
[+] AWS::Lambda::Permission SingletonLambda224e77f9a32e4b4dac32983477abba16/AllowSes SingletonLambda224e77f9a32e4b4dac32983477abba16AllowSesB42DF904
✨ Number of stacks with differences: 1
マネジメントコンソールから確認したデプロイ済みのスタックのリソース一覧です。
CustomResourceConfig を使用する
次に CustomResourceConfig を使用して、先述の 3 つのメソッドにより自動作成されるリソースをカスタマイズします。
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as ses from 'aws-cdk-lib/aws-ses';
import * as log from 'aws-cdk-lib/aws-logs';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { CustomResourceConfig } from 'aws-cdk-lib/custom-resources';
export class SampleApp extends cdk.Stack {
constructor(scope: Construct, id: string) {
super(scope, id);
const config = CustomResourceConfig.of(this);
config.addRemovalPolicy(cdk.RemovalPolicy.DESTROY); // 既定の Retain から変更
config.addLogRetentionLifetime(log.RetentionDays.ONE_DAY); // 指定の保持期間のロググループをあらかじめ作成
config.addLambdaRuntime(lambda.Runtime.NODEJS_18_X); // 既定の最新バージョンから変更
new ses.ReceiptRuleSet(this, 'RuleSet', {
dropSpam: true,
});
}
}
CDK Diff でデプロイした場合の差分を確認すると、Lambda 関数のランタイムバージョンが変更され、Log group が作成されて Lambda 関数に紐づけられていることが分かります。
$ npx cdk diff -- SampleApp
start: Building 9447d8b0d19a05509e2e82f993dedde2fffa48bb9d4794533485b015ad0130f8:current_account-current_region
success: Built 9447d8b0d19a05509e2e82f993dedde2fffa48bb9d4794533485b015ad0130f8:current_account-current_region
start: Publishing 9447d8b0d19a05509e2e82f993dedde2fffa48bb9d4794533485b015ad0130f8:current_account-current_region
success: Published 9447d8b0d19a05509e2e82f993dedde2fffa48bb9d4794533485b015ad0130f8:current_account-current_region
Hold on while we create a read-only change set to get a diff with accurate replacement information (use --no-change-set to use a less accurate but faster template-only diff)
Stack SampleApp
Resources
[+] AWS::Logs::LogGroup SingletonLambda224e77f9a32e4b4dac32983477abba16/Resource/logGroup SingletonLambda224e77f9a32e4b4dac32983477abba16logGroupCB6CF95E
[~] AWS::Lambda::Function SingletonLambda224e77f9a32e4b4dac32983477abba16 SingletonLambda224e77f9a32e4b4dac32983477abba164533EA15
├─ [+] LoggingConfig
│ └─ {"LogGroup":{"Ref":"SingletonLambda224e77f9a32e4b4dac32983477abba16logGroupCB6CF95E"}}
└─ [~] Runtime
└─ @@ -1,9 +1,1 @@
[-] {
[-] "Fn::FindInMap": [
[-] "LatestNodeRuntimeMap",
[-] {
[-] "Ref": "AWS::Region"
[-] },
[-] "value"
[-] ]
[-] }
[+] "nodejs18.x"
✨ Number of stacks with differences: 1
CDK デプロイしたスタックをマネジメントコンソールから確認すると、リソースとして Log group が作成されています。
また Lambda 関数をコンソールから確認すると、作成された Log group が紐づいています。
CloudFormation のテンプレートで作成された Log group を確認すると、RetentionInDays が 1 に設定され、DeletionPolicy が Delete に設定されています。
"SingletonLambda224e77f9a32e4b4dac32983477abba16logGroupCB6CF95E": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"RetentionInDays": 1
},
"DependsOn": [
"SingletonLambda224e77f9a32e4b4dac32983477abba16ServiceRole3037F5B4"
],
"UpdateReplacePolicy": "Delete",
"DeletionPolicy": "Delete",
"Metadata": {
"aws:cdk:path": "SampleApp/SingletonLambda224e77f9a32e4b4dac32983477abba16/Resource/logGroup/Resource"
}
},
CustomResourceConfig で行った設定がデプロイしたリソースに反映されていることが確認できました。
CustomResourceConfig が使えないパターン
次のようなパターンでは CustomResourceConfig が使えません。当初私は「removalPolicy
をすべてのリソースに一括設定できるなんて便利じゃん!」なんて思っていましたが、実際は一部のリソースにしか適用できません。
- Log group 以外のリソースの保持期間と DeletionPolicy の設定
- LogGroup コンストラクトクラスにより明示的に作成した Log group の設定
- Bucket コンストラクトクラスの autoDeleteObjects の設定により作成される Lambda 関数および Log group の設定
おわりに
AWS CDK で CustomResourceConfig クラスを使って、自動作成されるカスタムリソースをカスタマイズする方法についてご紹介しました。
これにより例えば、暗黙的に作成されたリソースが CDK スタックを削除した後にも削除されず残ったり、Lamabda 関数が古くて Truster Advisor で警告が出たり、という事態を回避することができます。CDK によるシステムの IaC 化をより細かいところまで行き届かせることができるので、Experimental であることに注意しつつ活用してみたいですね。
以上